package com.ytd.common.util;


import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Arrays;

/**
 * Author by Winds on 2016/10/18.
 * Email heardown@163.com.
 */
public class ByteUtil {

    private ByteUtil() {

    }

    private static char forDigit(int digit, int radix) {
        if ((digit >= radix) || (digit < 0)) {
            return '\0';
        }
        if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX)) {
            return '\0';
        }
        if (digit < 10) {
            return (char) ('0' + digit);
        }
        return (char) ('A' - 10 + digit);
    }

    public static String byte2Hex(byte num) {
        return value2Hex(num);
    }

    public static String short2Hex(short num) {
        return value2Hex(num);
    }

    public static String int2Hex(int num) {
        return value2Hex(num);
    }

    public static String long2Hex(long num) {
        return value2Hex(num);
    }

    /**
     * 显示数值的16进制字符
     *
     * @param number
     * @return
     */
    public static String value2Hex(Number number) {
        byte[] bytes = null;
        if (number instanceof Byte) {
            bytes = long2bytes(number.byteValue(), 1);
        } else if (number instanceof Short) {
            bytes = long2bytes(number.shortValue(), 2);
        } else if (number instanceof Integer) {
            bytes = long2bytes(number.intValue(), 4);
        } else if (number instanceof Long) {
            bytes = long2bytes(number.longValue(), 8);
        }

        if (bytes == null) {
            return "00";
        }

        return bytes2HexStr(bytes);
    }

    /**
     * 字节数组转换成对应的16进制表示的字符串
     *
     * @param src
     * @return
     */
    public static String bytes2HexStr(byte[] src) {
        StringBuilder builder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return "";
        }
        char[] buffer = new char[2];
        for (int i = 0; i < src.length; i++) {
            buffer[0] = forDigit((src[i] >>> 4) & 0x0F, 16);
            buffer[1] = forDigit(src[i] & 0x0F, 16);
            builder.append(buffer);
        }
        return builder.toString();
    }

    /**
     * 十六进制字节数组转字符串
     *
     * @param src 目标数组
     * @param dec 起始位置
     * @param length 长度
     * @return
     */
    public static String bytes2HexStr(byte[] src, int dec, int length) {
        byte[] temp = new byte[length];
        System.arraycopy(src, dec, temp, 0, length);
        return bytes2HexStr(temp);
    }

    /**
     * 16进制字符串转10进制数字
     *
     * @param hex
     * @return
     */
    public static long hexStr2decimal(String hex) {
        return Long.parseLong(hex, 16);
    }

    /**
     * 把十进制数字转换成足位的十六进制字符串,并补全空位
     *
     * @param num
     * @return
     */
    public static String decimal2fitHex(long num) {
        String hex = Long.toHexString(num).toUpperCase();
        if (hex.length() % 2 != 0) {
            return "0" + hex;
        }
        return hex.toUpperCase();
    }

    /**
     * 把十进制数字转换成足位的十六进制字符串,并补全空位
     *
     * @param num
     * @param strLength 字符串的长度
     * @return
     */
    public static String decimal2fitHex(long num, int strLength) {
        String hexStr = decimal2fitHex(num);
        StringBuilder stringBuilder = new StringBuilder(hexStr);
        while (stringBuilder.length() < strLength) {
            stringBuilder.insert(0, '0');
        }
        return stringBuilder.toString();
    }

    /**
     * 数字前补零
     *
     * @param dicimal
     * @param strLength
     * @return
     */
    public static String fitDecimalStr(int dicimal, int strLength) {
        StringBuilder builder = new StringBuilder(String.valueOf(dicimal));
        while (builder.length() < strLength) {
            builder.insert(0, "0");
        }
        return builder.toString();
    }

    /**
     * 字符串转十六进制字符串
     *
     * @param str
     * @return
     */
    public static String str2HexString(String str) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder();
        byte[] bs = null;
        try {
            bs = str.getBytes(Charset.forName("utf8"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
        }
        return sb.toString();
    }

    /**
     * 把十六进制表示的字节数组字符串，转换成十六进制字节数组
     *
     * @param
     * @return byte[]
     */
    public static byte[] hexStr2bytes(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toUpperCase().toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (hexChar2byte(achar[pos]) << 4 | hexChar2byte(achar[pos + 1]));
        }
        return result;
    }

    /**
     * int类型转成高位在前的字节数组
     *
     * @param ori
     * @param arrayAmount 字节数组长度
     * @return
     */
    public static byte[] long2bytes(long ori, int arrayAmount) {
        byte[] bytes = new byte[arrayAmount];
        for (int i = 0; i < arrayAmount; i++) {
            // 高位在前
            bytes[i] = (byte) ((ori >>> (arrayAmount - i - 1) * 8) & 0xff);
        }
        return bytes;
    }

    /**
     * int类型转成高位在前的字节数组
     *
     * @param ori
     * @param arrayAmount 字节数组长度
     * @return
     */
    public static byte[] long2bytes(long ori, byte[] targetBytes, int offset, int arrayAmount) {
        for (int i = 0; i < arrayAmount; i++) {
            // 高位在前
            targetBytes[offset + i] = (byte) ((ori >>> (arrayAmount - i - 1) * 8) & 0xff);
        }
        return targetBytes;
    }

    /**
     * 字节数组（高位在前）转换成对应的非负整数
     *
     * @param ori 需要转换的字节数组
     * @param offset 目标位置偏移
     * @param len 目标数组长度
     * @return
     */
    public static long bytes2long(byte[] ori, int offset, int len) {
        long result = 0;
        for (int i = 0; i < len; i++) {
            result = result | ((0xffL & ori[offset + i]) << (len - 1 - i) * 8);
        }
        return result;
    }

    /**
     * 字节数组（高位在前）转换成对应的非负整数
     *
     * @param ori 需要转换的字节数组
     * @return
     */
    public static long bytes2long(byte[] ori) {
        return bytes2long(ori, 0, ori.length);
    }

    /**
     * 把16进制字符[0123456789abcde]（含大小写）转成字节
     *
     * @param c
     * @return
     */
    private static int hexChar2byte(char c) {
        switch (c) {
            case '0':
                return 0;
            case '1':
                return 1;
            case '2':
                return 2;
            case '3':
                return 3;
            case '4':
                return 4;
            case '5':
                return 5;
            case '6':
                return 6;
            case '7':
                return 7;
            case '8':
                return 8;
            case '9':
                return 9;
            case 'a':
            case 'A':
                return 10;
            case 'b':
            case 'B':
                return 11;
            case 'c':
            case 'C':
                return 12;
            case 'd':
            case 'D':
                return 13;
            case 'e':
            case 'E':
                return 14;
            case 'f':
            case 'F':
                return 15;
            default:
                return -1;
        }
    }

    /**
     * 转换二进制数值
     *
     * @param value 要转换的数值
     * @param byteLen 该值占用的字节大小
     * @param withDivider 是否每8个bit增加一个分隔符
     * @return
     */
    public static String toBinString(long value, int byteLen, boolean withDivider) {

        int bitLen = byteLen * 8;

        char[] chars = new char[bitLen];
        Arrays.fill(chars, '0');
        int charPos = bitLen;
        do {
            --charPos;
            if ((value & 1) > 0) {
                chars[charPos] = '1';
            }
            value >>>= 1;
        } while (value != 0 && charPos > 0);

        if (withDivider && byteLen > 1) {
            StringBuilder stringBuilder = new StringBuilder();

            boolean alreadyAppend = false;
            for (int i = 0; i < byteLen; i++) {
                if (alreadyAppend) {
                    stringBuilder.append(' ');
                } else {
                    alreadyAppend = true;
                }
                stringBuilder.append(chars, i * 8, 8);
            }

            return stringBuilder.toString();
        }

        return new String(chars);
    }

    /**
     * 转换二进制数值
     *
     * @param value 要转换的数值
     * @param byteLen 该值占用的字节大小
     * @return
     */
    public static String toBinString(long value, int byteLen) {
        return toBinString(value, byteLen, true);
    }

    /**
     * 异或校验和
     *
     * @param bytes
     * @param offset
     * @param len
     * @return
     */
    public static byte getXOR(byte[] bytes, int offset, int len) {
        // 计算校验和
        byte toDiff = 0;
        // 校验和为除开校验位外的所有数据做异或
        for (int i = 0; i < len; i++) {
            toDiff = (byte) (toDiff ^ bytes[i + offset]);
        }
        return toDiff;
    }

    public static int getBitFromLeft(byte[] bytes, int dataOffset, int bitPos) {
        int byteIndex = (bitPos - 1) / 8;
        int bitIndex = (bitPos - 1) % 8;
        if ((bytes[dataOffset + byteIndex] & (1 << bitIndex)) != 0) {
            return 1;
        }
        return 0;
    }

    public static String strTo16(String s) {
        String str = "";

        for (int i = 0; i < s.length(); ++i) {
            int ch = s.charAt(i);
            String s4 = Integer.toHexString(ch);
            str = str + s4;
        }

        return str;
    }

    public static String hexStringToString(String s) {
        if (s != null && !s.equals("")) {
            s = s.replace(" ", "");
            byte[] baKeyword = new byte[s.length() / 2];

            for (int i = 0; i < baKeyword.length; ++i) {
                try {
                    baKeyword[i] = (byte) (255 & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
                } catch (Exception var5) {
                    var5.printStackTrace();
                }
            }

            try {
                s = new String(baKeyword, "UTF-8");
                new String();
            } catch (Exception var4) {
                var4.printStackTrace();
            }

            return s;
        } else {
            return null;
        }
    }

    public static byte[] hex2byte(String hex) {
        String digital = "0123456789ABCDEF";
        String hex1 = hex.replace(" ", "");
        char[] hex2char = hex1.toCharArray();
        byte[] bytes = new byte[hex1.length() / 2];

        for (int p = 0; p < bytes.length; ++p) {
            byte temp = (byte) (digital.indexOf(hex2char[2 * p]) * 16);
            temp = (byte) (temp + digital.indexOf(hex2char[2 * p + 1]));
            bytes[p] = (byte) (temp & 255);
        }

        return bytes;
    }

    public static String bytes2HexString(byte[] b, int size) {
        String ret = "";

        for (int i = 0; i < size; ++i) {
            String hex = Integer.toHexString(b[i] & 255);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }

            ret = ret + hex.toUpperCase();
        }

        return ret;
    }

    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src != null && src.length > 0) {
            for (int i = 0; i < src.length; ++i) {
                int v = src[i] & 255;
                String hv = Integer.toHexString(v);
                if (hv.length() < 2) {
                    stringBuilder.append(0);
                }

                stringBuilder.append(hv);
            }

            return stringBuilder.toString();
        } else {
            return null;
        }
    }

    public static String byteToStr(byte[] b, int size) {
        String ret = "";

        for (int i = 0; i < size; ++i) {
            String hex = Integer.toHexString(b[i] & 255);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }

            ret = ret + hex.toUpperCase();
        }

        return ret;
    }

    public static String getCRC_16(byte[] bytes) {
        int CRC = 65535;
        int POLYNOMIAL = 'ꀁ';

        for (int i = 0; i < bytes.length; ++i) {
            CRC ^= bytes[i] & 255;

            for (int j = 0; j < 8; ++j) {
                if ((CRC & 1) != 0) {
                    CRC >>= 1;
                    CRC ^= POLYNOMIAL;
                } else {
                    CRC >>= 1;
                }
            }
        }

        if (Integer.toHexString(CRC).toUpperCase().length() == 2) {
            return byteToStr(bytes, bytes.length) + "00" + Integer.toHexString(CRC).toUpperCase();
        } else if (Integer.toHexString(CRC).toUpperCase().length() == 3) {
            return byteToStr(bytes, bytes.length) + "0" + Integer.toHexString(CRC).toUpperCase();
        } else {
            return byteToStr(bytes, bytes.length) + Integer.toHexString(CRC).toUpperCase();
        }
    }

    public static String getSum16(byte[] msg, int length) {
        long mSum = 0L;
        byte[] mByte = new byte[length];
        byte[] var5 = msg;
        int var6 = msg.length;

        for (int var7 = 0; var7 < var6; ++var7) {
            byte byteMsg = var5[var7];
            long mNum = (long) byteMsg >= 0L ? (long) byteMsg : (long) byteMsg + 256L;
            mSum += mNum;
        }

        for (int liv_Count = 0; liv_Count < length; ++liv_Count) {
            mByte[length - liv_Count - 1] = (byte) ((int) (mSum >> liv_Count * 8 & 255L));
        }

        return byteToStr(msg, length) +
            byteToStr(mByte, mByte.length).substring(byteToStr(mByte, mByte.length).length() - 4,
                byteToStr(mByte, mByte.length).length());
    }

    public static byte[] charToBytes(char c) {
        byte[] b = new byte[] {(byte) ((c & '\uff00') >> 8), (byte) (c & 255)};
        return b;
    }

    public static char bytesToChar(byte[] b) {
        char c = (char) ((b[0] & 255) << 8 | b[1] & 255);
        return c;
    }

    public static int exchangeSn(byte[] b) {
        int ret = 0;
        ret += b[0] & 255;
        ret += (b[1] & 255) << 8;
        return ret;
    }

    public static String charToHexString(char c) {
        StringBuilder ret = new StringBuilder();
        byte[] b = new byte[] {(byte) ((c & '\uff00') >> 8), (byte) (c & 255)};

        for (int i = 0; i < 2; ++i) {
            String hex = Integer.toHexString(b[i]);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }

            ret.append(hex.toUpperCase());
        }

        return ret.toString();
    }

    public static String byteToHexString(byte b) {
        String ret = Integer.toHexString(b & 255);
        if (ret.length() == 1) {
            ret = '0' + ret;
        }

        return ret;
    }

    public static byte[] swap(byte[] data) {
        int length = data.length;
        if (length == 1) {
            return data;
        } else {
            byte[] dest = new byte[length];

            for (int i = 0; i < length; ++i) {
                dest[i] = data[length - i - 1];
            }

            return dest;
        }
    }

    public static String byteToBinaryString(byte b) {
        return Integer.toBinaryString((b & 255) + 256).substring(1);
    }

    public static int bytesToInt(byte[] src, int offset) {
        int value = src[offset] & 255 | (src[offset + 1] & 255) << 8 | (src[offset + 2] & 255) << 16 |
            (src[offset + 3] & 255) << 24;
        return value;
    }

    public static int bytesToInt2(byte[] src, int offset) {
        int value = (src[offset] & 255) << 24 | (src[offset + 1] & 255) << 16 | (src[offset + 2] & 255) << 8 |
            src[offset + 3] & 255;
        return value;
    }

    public static int bytesToInt3(byte[] src) {
        int value = src[0] & 255 | (src[1] & 255) << 8;
        return value;
    }

    public static int bytesToInt4(byte[] src) {
        int value = src[1] & 255 | (src[0] & 255) << 8;
        return value;
    }

    public static int bytesToInt5(byte[] src, boolean swap) {
        if (swap) {
            src = swap(src);
        }

        int value = src[2] & 255 | (src[1] & 255) << 8 | (src[0] & 255) << 16;
        return value;
    }

    public static int byteToInt(byte b) {
        int value = b & 255;
        return value;
    }

    public static int getSnInt(byte[] src) {
        int value = src[0] & 255 | (src[1] & 255) << 8;
        return value;
    }

    public static byte[] getSnBytes(int snInt) {
        byte[] value = new byte[] {(byte) (snInt & 255), (byte) (snInt >> 8 & 255)};
        return value;
    }

    public static int getLenthInt(byte[] src) {
        int value = src[0] & 255 | (src[1] & 255) << 8;
        return value;
    }

    public static int getTcInt(byte[] tc) {
        int value = tc[0] & 255 | (tc[1] & 255) << 8;
        return value;
    }

    public static long bytesToLongValue(byte[] src, boolean needSwap) {
        long value = 0L;
        if (needSwap) {
            src = swap(src);
        }

        String srcString = bytesToHexString(src);
//        LogUtil.d("srcString = " + srcString);
        if (srcString != null) {
            value = Long.parseLong(srcString, 16);
        }

        return value;
    }

    public static byte[] longToBytesValue(long value, int size, boolean needSwap) {
        String valueStr = Long.toHexString(value);
        int rightLength = size * 2;
        int d = rightLength - valueStr.length();
        if (d > 0) {
            for (int i = 0; i < d; ++i) {
                valueStr = "0" + valueStr;
            }
        }

//        LogUtil.d("valueStr =" + valueStr);
        byte[] result = new byte[size];

        for (int j = 0; j < rightLength; j += 2) {
            String s = valueStr.substring(j, j + 2);
            int c = Integer.parseInt(s, 16);
//            LogUtil.d("c=" + c);
            byte b = (byte) (255 & c);
            result[j / 2] = b;
        }

        if (needSwap) {
            result = swap(result);
        }

//        LogUtil.d("longToBytesValue：value=" + value + " result =" + bytesToHexString(result) + " needSwap =" +
//        needSwap);
        return result;
    }

    public static String charsBytesToIntArray(byte[] chars, boolean needSwap) {
//        LogUtil.d("chars = " + bytesToHexString(chars));
        if (needSwap) {
            chars = swap(chars);
        }

        StringBuilder result = new StringBuilder();
        byte[] var3 = chars;
        int var4 = chars.length;

        for (int var5 = 0; var5 < var4; ++var5) {
            byte aChar = var3[var5];
            char c = (char) (aChar & 255);
            result.append(c);
        }

        return result.toString();
    }

    public static String bytesToNameString(byte[] src) {
//        LogUtil.d("bytesToNameString: chars = " + bytesToHexString(src));
        StringBuilder result = new StringBuilder();
        int length = src.length;

        for (int i = 0; i < length; i += 2) {
            try {
                String s_gbk = new String(new byte[] {src[i], src[i + 1]}, "GBK");
                result.append(s_gbk);
            } catch (UnsupportedEncodingException var5) {
                var5.printStackTrace();
            }
        }

        return result.toString();
    }

    public static byte[] stringToCharToBytes(String s) {
        byte[] result = new byte[s.length()];

        for (int i = 0; i < s.length(); ++i) {
            char c = s.charAt(i);
            String hexInt = Integer.toHexString(c);
            byte b = (byte) Integer.parseInt(hexInt, 16);
//            LogUtil.d("b=" + byteToHexString(b));
            result[i] = b;
        }

        return result;
    }

    public static String charBytesToString(byte[] src) {
        StringBuilder sb = new StringBuilder();
        byte[] var2 = src;
        int var3 = src.length;

        for (int var4 = 0; var4 < var3; ++var4) {
            byte b = var2[var4];
            char c = (char) (b & 255);
            sb.append(c);
        }

        return sb.toString();
    }
}
